﻿using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
using YAPL.Language.Compiler.ILOptimization.Rewriters;
using YAPL.Language.Core.Types;

namespace YAPL.Language.Compiler.ILOptimization {
	public class PeepholeOptimizer {
		private readonly string _outputPath;
		private readonly List<IRewriter> _rewriters = new List<IRewriter>();
		public PeepholeOptimizer(string outputPath) {
			_outputPath = outputPath;


			var sampleRewriter = new ReplacementRewriter();
			sampleRewriter.AddReplacement(new List<OpCode> { OpCodes.Ldloc_0, OpCodes.Pop }, new List<OpCode>());
			sampleRewriter.AddReplacement(new List<OpCode> { OpCodes.Ldloc_1, OpCodes.Pop }, new List<OpCode>());
			sampleRewriter.AddReplacement(new List<OpCode> { OpCodes.Ldloc_2, OpCodes.Pop }, new List<OpCode>());
			sampleRewriter.AddReplacement(new List<OpCode> { OpCodes.Ldloc_3, OpCodes.Pop }, new List<OpCode>());
			sampleRewriter.AddReplacement(new List<OpCode> { OpCodes.Stloc_0, OpCodes.Ldloc_0 }, new List<OpCode> { OpCodes.Dup, OpCodes.Stloc_0 });
			sampleRewriter.AddReplacement(new List<OpCode> { OpCodes.Stloc_1, OpCodes.Ldloc_1 }, new List<OpCode> { OpCodes.Dup, OpCodes.Stloc_1 });
			sampleRewriter.AddReplacement(new List<OpCode> { OpCodes.Stloc_2, OpCodes.Ldloc_2 }, new List<OpCode> { OpCodes.Dup, OpCodes.Stloc_2 });
			sampleRewriter.AddReplacement(new List<OpCode> { OpCodes.Stloc_3, OpCodes.Ldloc_3 }, new List<OpCode> { OpCodes.Dup, OpCodes.Stloc_3 });
			_rewriters.Add(sampleRewriter);
		}

		public void RewriteAssembly() {
			var assembly = AssemblyFactory.GetAssembly(_outputPath);
			foreach (TypeDefinition typeDef in assembly.MainModule.Types) {
				var callMethods = typeDef.Methods.GetMethod(YAPLFunction.CALL_METHOD_NAME);
				if (callMethods.Length > 0) {
					var body = callMethods[0].Body;
					foreach (var rewriter in _rewriters) {
						rewriter.Rewrite(body);
					}
				}
			}
			AssemblyFactory.SaveAssembly(assembly, _outputPath);
		}
	}
}
